package com.tiger.poker.util;

import com.tiger.poker.controller.GoldenFlowers;
import com.tiger.poker.entity.Player;
import com.tiger.poker.entity.Poker;
import com.tiger.poker.enums.PlayerOperationStatusEnum;
import com.tiger.poker.enums.PlayerStatusEnum;
import com.tiger.poker.enums.PokerEnum;

import java.util.*;

/**
 * @author Rick on 2/12/19 2:52 PM
 */
public class PokerUtils {

    public static int CHIP_FIVE = 5;

    public static int CHIP_TEN = 10;


    public static final Random random = new Random();

    public static List<Poker> generate52Pokers() {
        List<Poker> pokerList = new ArrayList<>(52);

        for (int i = 1; i <= 13; i++) {
            for (int j = 1; j <= 4; j++) {
                if (i == 1) {
                    pokerList.add(new Poker(j, "A", i));
                } else if (i <= 10) {
                    pokerList.add(new Poker(j, String.valueOf(i), i));
                } else if (i == 11) {
                    pokerList.add(new Poker(j, "J", i));
                } else if (i == 12) {
                    pokerList.add(new Poker(j, "Q", i));
                } else {
                    pokerList.add(new Poker(j, "K", i));
                }
            }
        }

        return pokerList;
    }

    public static void playerOperationChange(List<Player> players) {

        int index = -1;

        for (int i = 0; i < players.size(); i++) {
            if (players.get(i).getOperationStatus() == PlayerOperationStatusEnum.ENABLE.getCode()) {
                index = i;
                break;
            }
        }

        players.get(index).setOperationStatus(PlayerOperationStatusEnum.DISABLE.getCode());

        if (index == players.size() - 1) {
            players.get(0).setOperationStatus(PlayerOperationStatusEnum.ENABLE.getCode());
        } else {
            players.get(index + 1).setOperationStatus(PlayerOperationStatusEnum.ENABLE.getCode());
        }

    }

    public static void lookCards(Player player) {
        if (player.getStatus() == PlayerStatusEnum.NOT_LOOK.getCode()) {
            player.setStatus(PlayerStatusEnum.LOOKED.getCode());
        }
    }

    public static void check(Player player) {

        if (player.getStatus() == PlayerStatusEnum.NOT_LOOK.getCode()) {
            player.setScore(player.getScore() - CHIP_FIVE);
            GoldenFlowers.score += CHIP_FIVE;
        } else if (player.getStatus() == PlayerStatusEnum.LOOKED.getCode()) {
            player.setScore(player.getScore() - CHIP_TEN);
            GoldenFlowers.score += CHIP_TEN;
        }

    }

    public static void giveUp(Player player) {
        player.setStatus(PlayerStatusEnum.GIVE_UP.getCode());
    }

    public static boolean canBattle(Set<Player> players) {

        int live = 0;
        for (Player player : players) {
            if (player.getStatus() == PlayerStatusEnum.NOT_LOOK.getCode()
                    || player.getStatus() == PlayerStatusEnum.LOOKED.getCode()) {
                live++;
            }
        }

        if (live == 2) {
            return true;
        } else {
            for (Player player : players) {
                if (player.getStatus() == PlayerStatusEnum.NOT_LOOK.getCode()) {
                    return false;
                }
            }
        }

        return true;
    }

    public static void dealtCard(Set<Player> players) {

        List<Poker> pokers = generate52Pokers();

        for (Player player : players) {
            List<Poker> pokerList = new ArrayList<>(3);
            for (int j = 0; j < 3; j++) {
                int index = random.nextInt(pokers.size() - 1);
                pokerList.add(pokers.get(index));
                pokers.remove(index);

            }
            player.setPokers(pokerList);
        }
    }

    public static Player battle2Death(Player challenger, Player player) {
        List<Poker> challengerPokers = challenger.getPokers();
        List<Poker> playerPokers = player.getPokers();

        challengerPokers.sort(Comparator.comparing(Poker::getNumber));
        playerPokers.sort(Comparator.comparing(Poker::getNumber));

        int challengerPokerType = getPokerType(challengerPokers);
        int playerPokerType = getPokerType(playerPokers);

        if (challengerPokerType == playerPokerType) {
            if (challengerPokerType == PokerEnum.LEOPARD.getCode()
                    && challengerPokerType == PokerEnum.FLUSH_STRAIGHT.getCode()
                    && challengerPokerType == PokerEnum.STRAIGHT.getCode()) {

                return challengerPokers.get(2).getNumber() <= playerPokers.get(2).getNumber() ? player : challenger;
            } else {
                return challengerPokerType == PokerEnum.PAIRS.getCode() ? comparePairs(challenger, player) : compareScatter(challenger, player);
            }
        } else {
            return challengerPokerType > playerPokerType ? player : challenger;
        }
    }

    private static Player compareScatter(Player challenger, Player player) {
        List<Poker> challengerPokers = challenger.getPokers();
        List<Poker> playerPokers = player.getPokers();

        int[] challengerNumber = sortOutScatter(challengerPokers);
        int[] playerNumber = sortOutScatter(playerPokers);

        for (int i = 2; i >= 0; i--) {
            if (challengerNumber[i] == playerNumber[i]) {
                continue;
            }
            return challengerNumber[i] > playerNumber[i] ? challenger : player;
        }

        //比到最后一个的时候还是相等的话,那就是player获胜
        return player;
    }

    /**
     * Sort out scatter.
     * 把散牌从小到大排序,如果是1也就是A的话,当作14处理
     *
     * @param pokers the challenger pokers
     * @return the int [ ]
     */
    private static int[] sortOutScatter(List<Poker> pokers) {
        int[] numbers = new int[3];
        if (pokers.get(0).getNumber() == 1) {
            numbers[2] = 14;
            numbers[0] = pokers.get(1).getNumber();
            numbers[1] = pokers.get(2).getNumber();
        } else {
            for (int i = 0; i < numbers.length; i++) {
                numbers[i] = pokers.get(i).getNumber();
            }
        }
        return numbers;
    }


    private static Player comparePairs(Player challenger, Player player) {
        int[] challengerPoker = sortOutPairs(challenger.getPokers());
        int[] playerPoker = sortOutPairs(player.getPokers());

        boolean pairsEqual = challengerPoker[0] == playerPoker[0];
        if (pairsEqual) {
            return challengerPoker[1] > playerPoker[1] ? challenger : player;
        } else {
            return challengerPoker[0] > playerPoker[0] ? challenger : player;
        }
    }


    /**
     * Sort out pairs.
     * 把对子牌型整理成一个数组,第一位放对子,第二位是散牌
     *
     * @param pokers the pokers
     * @return the int [ ]
     */
    private static int[] sortOutPairs(List<Poker> pokers) {
        int pair, single;
        if (pokers.get(0).equals(pokers.get(1))) {
            pair = pokers.get(0).getNumber();
            single = pokers.get(2).getNumber();
        } else if (pokers.get(0).equals(pokers.get(2))) {
            pair = pokers.get(0).getNumber();
            single = pokers.get(1).getNumber();
        } else {
            pair = pokers.get(1).getNumber();
            single = pokers.get(0).getNumber();
        }
        if (pair == 1) {
            pair = 14;
        }
        if (single == 1) {
            single = 14;
        }
        return new int[]{pair, single};
    }

    public static boolean isLeopard(List<Poker> pokers) {

        if (pokers.size() != 3) {
            return false;
        }

        if (pokers.get(0).getNumber().intValue() == pokers.get(1).getNumber()
                && pokers.get(0).getNumber().intValue() == pokers.get(2).getNumber()) {
            return true;
        }

        return false;
    }

    public static boolean isFlushStraight(List<Poker> pokers) {
        if (pokers.size() != 3) {
            return false;
        }

        pokers.sort(Comparator.comparing(Poker::getNumber));

        if (pokers.get(0).getColor().intValue() == pokers.get(1).getColor()
                && pokers.get(0).getColor().intValue() == pokers.get(2).getColor()) {

            return isStraight(pokers);

        } else {
            return false;
        }

    }

    public static boolean isFlush(List<Poker> pokers) {
        if (pokers.size() != 3) {
            return false;
        }

        pokers.sort(Comparator.comparing(Poker::getNumber));

        if (pokers.get(0).getColor().intValue() == pokers.get(1).getColor()
                && pokers.get(0).getColor().intValue() == pokers.get(2).getColor()) {

            return true;

        } else {
            return false;
        }

    }

    public static boolean isStraight(List<Poker> pokers) {
        if (pokers.size() != 3) {
            return false;
        }

        pokers.sort(Comparator.comparing(Poker::getNumber));

        if (pokers.get(0).getNumber() == 1 && pokers.get(1).getNumber() == 12 && pokers.get(2).getNumber() == 13) {
            return true;
        } else if (pokers.get(0).getNumber() + 1 == pokers.get(1).getNumber()
                && pokers.get(1).getNumber() + 1 == pokers.get(2).getNumber()) {
            return true;
        } else {
            return false;
        }

    }

    public static boolean isPairs(List<Poker> pokers) {
        if (pokers.size() != 3) {
            return false;
        }
        pokers.sort(Comparator.comparing(Poker::getNumber));

        if (pokers.get(0).getNumber().intValue() == pokers.get(1).getNumber()
                || pokers.get(1).getNumber().intValue() == pokers.get(2).getNumber()) {
            return true;
        }

        return false;
    }

    public static int getPokerType(List<Poker> pokers) {
        if (pokers.size() != 3) {
            return 0;
        }

        if (isLeopard(pokers)) {
            return 1;
        } else if (isFlushStraight(pokers)) {
            return 2;
        } else if (isFlush(pokers)) {
            return 3;
        } else if (isStraight(pokers)) {
            return 4;
        } else if (isPairs(pokers)) {
            return 5;
        } else {
            return 6;
        }
    }

}
